package com.hui.config.security;

import com.hui.config.security.smscode.SmsSecurityConfigurerAdapter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @apiNote 参考网址：http://www.jb51.net/article/105844.htm
 * UserDetailsService.loadUserByUsername() -->
 * AbstractUserDetailsAuthenticationProvider.retrieveUser() --> 重新从数据源获取用户信息
 * <p>
 * AbstractUserDetailsAuthenticationProvider.authenticate() --> 认证
 * 这个方法会先到缓存中查找user:
 * 如果没有的话会从上一步DaoAuthenticationProvider的loadUserByUsername方法把user查出来。
 * 这里会抛UsernameNotFoundException这个异常, 应该是用户不存在这个错误, 即Bad credentials.
 * <p>
 * AbstractUserDetailsAuthenticationProvider.additionalAuthenticationChecks() --> 登录逻辑处理
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

//    @Autowired
//    private ValidateCodeFilter validateCodeFilter;
//
//    @Autowired
//    private CustomerAuthenticationProvider customerAuthenticationProvider;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    private SmsSecurityConfigurerAdapter smsSecurityConfigurerAdapter;

    /**
     * 配置认证源
     *
     * @apiNote inMemoryAuthentication内存中获取
     * auth.inMemoryAuthentication().withUser("user").password("123456").roles("USER");
     * @apiNote jdbcAuthentication从数据库中获取，但是默认是以security提供的表结构
     * @apiNote usersByUsernameQuery 指定查询用户SQL
     * @apiNote auth.jdbcAuthentication().dataSource(dataSource).usersByUsernameQuery(query).authoritiesByUsernameQuery(query);
     * @apiNote 注入userDetailsService，需要实现userDetailsService接口
     * auth.userDetailsService(userDetailsService);
     * @apiNote authenticationProvider自定义权限提供
     * auth.authenticationProvider(authenticationProvider);
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        auth.authenticationProvider(customerAuthenticationProvider);
        auth.inMemoryAuthentication()
                .withUser("admin")
                .password(new BCryptPasswordEncoder().encode("123456"))
                .authorities("Admin");
    }

    /**
     * 访问权限的配置
     *
     * @apiNote 参考网址：http://blog.csdn.net/zhoucheng05_13/article/details/60467234
     * @apiNote 参考网址：http://357029540.iteye.com/blog/2329730
     * @apiNote 参考网址：https://segmentfault.com/a/1190000010672041
     * @apiNote 顺序
     * 有从上到下，从左到右的顺序
     * 注意，将最不具体的路径（如anyRequest()）放在最后面。如果不这样做，那不具体的路径配置将会覆盖掉更为具体的路径配置。
     * @apiNote 方法
     * antMatchers()方法所设定的路径支持Ant风格的通配符
     * regexMatchers()方法能够接受正则表达式来定义请求路径
     * anyRequest()//其他方法
     * @apiNote 规则
     * .permitAll()//没有任何的安全限制
     * .authenticated()//必须已经登录
     * .hasIpAddress()来自哪个IP地址
     * .denyAll()//始终不允许
     * .permitAll()//始终允许
     * .rememberMe()
     * .hasRole()
     * .hasAnyRole()
     * .access()//如果以上可行，该方法支持组合验证（.access("hasRole('SPITTER') and hasIpAddress('127.0.0.1')");）
     * //在注册表单中，用户会希望敏感信息（用户不希望泄露的信息，如信用卡号等）是私密的。为了保证注册表单的数据通过HTTPS传送，我们可以在配置中添加requiresChannel()方法
     */
//    @Override
//    protected void configure(HttpSecurity http) throws Exception {
//        http
//                .csrf().disable()
//                .authorizeRequests()//配置安全策略
//
//                .antMatchers(
//                        "/swagger**", //swagger
//                        "/webjars/**", //swagger
//                        "/swagger-resources/**", //swagger
//                        "/v2/*" //swagger
//                ).permitAll()//请求不需要验证
//                .anyRequest().fullyAuthenticated()//其余的所有请求都需要验证,有顺序
//                .withObjectPostProcessor(
//                        new ObjectPostProcessor<FilterSecurityInterceptor>() {
//                            public <O extends FilterSecurityInterceptor> O postProcess(O fsi) {
//                                fsi.setSecurityMetadataSource(new MyFilterInvocationSecurityMetadataSource());
//                                fsi.setAccessDecisionManager(new MyAccessDecisionManager());
//                                return fsi;
//                            }
//                        })
//                .and()
//                .formLogin()
//                .loginProcessingUrl("/login")
//                .successHandler(new RestAuthenticationSuccessHandler())//登录成功后的处理
//                .failureHandler(new RestAuthenticationFailureHandler())//认证失败后的处理
//                .and()
//                .logout().logoutSuccessHandler(new RestLogoutHandler())//登出后的处理
//                .and()
//                .exceptionHandling()
//                .accessDeniedHandler(new RestAccessDeniedHandler())//没有权限的处理
//                .authenticationEntryPoint(new RestAuthenticationEntryPoint())//没有登录的处理
//                .and()
//                .logout()
//                .logoutUrl("/logout")
//                .clearAuthentication(true)
//                .and()
//                .sessionManagement()
//                .maximumSessions(1)
//                .sessionRegistry(new SessionRegistryImpl())//sessionDAO
//                .expiredSessionStrategy(new RestSessionInformationExpiredStrategy())//session策略
//        ;
//    }
//    @Override
//    protected void configure(HttpSecurity http) throws Exception {
//        http
//                .csrf().disable()
//                .authorizeRequests()//配置安全策略
//                .antMatchers(
//                        "/swagger**", //swagger
//                        "/webjars/**", //swagger
//                        "/swagger-resources/**", //swagger
//                        "/v2/*" //swagger
//                ).permitAll()//请求不需要验证
////                .antMatchers("/selectAllUser").hasRole("ADMIN")
//                .anyRequest().fullyAuthenticated()//其余的所有请求都需要验证,有顺序
//                .and()
//                .formLogin()
//                .loginProcessingUrl("/login")
//                .successHandler(new RestAuthenticationSuccessHandler())//登录成功后的处理
//                .failureHandler(new RestAuthenticationFailureHandler())//认证失败后的处理
//                .and()
//                .logout().logoutSuccessHandler(new RestLogoutHandler())//登出后的处理
//                .and()
//                .exceptionHandling()
//                .accessDeniedHandler(new RestAccessDeniedHandler())//没有权限的处理
//                .authenticationEntryPoint(new RestAuthenticationEntryPoint())//没有登录的处理
//                .and()
//                .logout()
//                .logoutUrl("/logout")
//                .clearAuthentication(true)
//        ;
//    }
//    @Override
//    protected void configure(HttpSecurity http) throws Exception {
//
//        http
//                .addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
//                .authorizeRequests()
//                .anyRequest().authenticated()
//                .and()
//                .formLogin().and()
//                .httpBasic();
//    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 关闭csrf，开启跨域支持
        http.csrf().disable().cors();
        http.authorizeRequests()
                .antMatchers("/sms/send/code", "/sms/login").permitAll()
                .anyRequest()
                .authenticated()
                .and()
                .formLogin()
                .and()
                .httpBasic();
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
        // 添加手机号短信登录
        http.apply(smsSecurityConfigurerAdapter);
    }
}
